import { EventEmitter } from "./core/EventEmitter"
type Data = number[]

export class Meachine {
  _busList: Bus[] = []
  _addrList: number[] = []
  _name: string = ""
  event: EventEmitter = new EventEmitter()
  constructor() {
  }
  bindBus(bus: Bus) {
    bus.onOutput((data: Data) => {
      console.log("Meachine bind onOutput data", data);
      this.input(data, bus)
    })
    const addr = bus.getAddr()
    this._addrList.push(addr)
    this._busList.push(bus)
    return { addr }
  }
  removeBus(bus: Bus) {
    this._busList = this._busList.filter(item => item !== bus)
  }
  afterInput(data: Data) { }
  _lastInputAddr: number = 0
  input(data: Data, bus: Bus) {
    // 判断 Bus 是否存在
    if (!bus && !this._busList.length) return;
    const busIndex = bus ? this._busList.indexOf(bus) : 0;
    if (busIndex === -1) return;
    const addr = this._addrList[busIndex]
    if (data[0] !== addr || data[1] === addr) return;
    const filterData = data.slice(2)
    console.log("Meachine input before afterInput", data, bus, filterData);
    this._lastInputAddr = data[1]
    this.afterInput(filterData)
  }
  beforeOutput(data: Data) {
    this.output(data, 0)
  }
  output(data: Data, device: number = 0, busList: Bus[] = this._busList) {
    busList.forEach((bus) => {
      const index = this._busList.indexOf(bus)
      if (index === -1) return;
      const addr = this._addrList[index]
      const outputData = [this._lastInputAddr, addr, ...data]
      console.log("Meachine output data", outputData);
      bus.input(outputData)
    })
  }
}

export class Bus {
  constructor() { }
  event: EventEmitter = new EventEmitter()
  input(data: any) {
    console.log("Bus  input data", data);
    this.event.$emit("output", data)
  }
  onOutput(callback: Function) {
    this.event.$on("output", callback)
  }
  getAddr(): number {
    const output = this.event.getEventList("output");
    return output.length
  }
}

export class Register extends Meachine {
  memory: number[] = []
  constructor(Bits: number) {
    super()
    this.memory = new Array(Bits).fill(0)
  }
  afterInput(data: Data) {
    console.log("Register afterInput data", data);
    const [mode, addr, inputData] = data
    if (mode === 0) {
      // read
      const outputData = this.memory[addr]
      console.log("Register afterInput outputData", outputData);
      return this.beforeOutput([outputData])
    }
    if (mode === 1) {
      // write
      this.memory[addr] = inputData
      return;
    }
  }
  beforeOutput(data: Data) {
    // create command to output
    this.output(data)
    return data
  }
}